home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / pascal / async12.zip / ASYNC12.ASM < prev    next >
Assembly Source File  |  1989-05-04  |  22KB  |  749 lines

  1. ;********************************************************
  2. ;*                            *
  3. ;*    Low-level serial communications handlers    *
  4. ;*        For ASYNC11 - Turbo Pascal V5.0        *
  5. ;*                            *
  6. ;*    Copyright (C) 1988, Rising Edge Data Services     *
  7. ;*                            *
  8. ;*   Assembled with the Borland TURBO ASSEMBER (V1.0)    *
  9. ;*                            *
  10. ;*  Author: M. Schultz        Ver 1.1 - Thu 05/04/89    *
  11. ;*                            *
  12. ;********************************************************
  13.  
  14. ;    Status byte definition (C_Status):
  15.  
  16. ;    7   6   5   4   3   2   1   0
  17. ;    |   |   |   |   |   |   |   |____ Input buffer empty
  18. ;    |   |   |   |   |   |   |________ Input buffer full
  19. ;    |   |   |   |   |   |____________ Output buffer empty
  20. ;    |   |   |   |   |________________ Output buffer full
  21. ;    |   |   |   |____________________ Input buffer overflow
  22. ;    |   |   |________________________ Output buffer overflow
  23. ;    |   |____________________________ Hard handshake active (xmit stopped)
  24. ;    |________________________________ Soft handshake active (xmit stopped)
  25.  
  26. ;    Control byte definition (C_Ctrl):
  27.  
  28. ;    7   6   5   4   3   2   1   0
  29. ;    |   |   |   |   |   |   |   |____ Enable RTS handshake
  30. ;    |   |   |   |   |   |   |________ Enable CTS handshake
  31. ;    |   |   |   |   |   |____________ Enable software handshake
  32. ;    |   |   |   |   |________________
  33. ;    |   |   |   |____________________
  34. ;    |   |   |________________________
  35. ;    |   |____________________________
  36. ;    |________________________________ XL3 communications mode
  37.  
  38.     IDEAL
  39.  
  40.     SEGMENT    DATA     WORD PUBLIC
  41.  
  42. ;    Externally accessed (TP program) variables
  43. ;    Note:     Most of these variables are declared as arrays in the main
  44. ;        program; i.e. C_InSize : Array[1..4] Of Word
  45.  
  46.     EXTRN    C_InBufPtr :DWORD    ;Pointer to input buffers
  47.     EXTRN    C_OutBufPtr:DWORD    ;Pointer to output buffers
  48.     EXTRN    C_InSize   :WORD    ;Size (bytes) of input buffers
  49.     EXTRN    C_OutSize  :WORD    ;Size (bytes) of output buffers
  50.     EXTRN    C_InHead   :WORD    ;Input (receive) head pointers
  51.     EXTRN    C_OutHead  :WORD    ;Output (transmit) head pointers
  52.     EXTRN    C_InTail   :WORD    ;Input (receive) tail pointers
  53.     EXTRN    C_OutTail  :WORD    ;Output (transmit) tail pointers
  54.     EXTRN    C_RTSOn    :WORD    ;Point at which RTS line is asserted
  55.     EXTRN    C_RTSOff   :WORD    ;Point at which RTS line is dropped
  56.     EXTRN    C_StartChar:BYTE    ;Start character for soft handshake
  57.     EXTRN    C_StopChar :BYTE    ;Stop character for soft handshake
  58.     EXTRN    C_Status   :BYTE    ;Status byte (see above)
  59.     EXTRN    C_Ctrl     :BYTE    ;Control byte (see above)
  60.     EXTRN    C_PortOpen :BYTE    ;Port-open flags
  61.     EXTRN    C_PortAddr :WORD    ;Base address of ports
  62.     EXTRN    C_MaxCom   :BYTE    ;Highest port # defined (single byte)
  63.     EXTRN    C_XL3Ptr   :BYTE    ;String index, detection of XL3 ID
  64.     EXTRN    C_Temp     :WORD    ;Used for debugging
  65.  
  66. ;    8250 register offsets
  67.  
  68. IER    EQU    1            ;Interrupt enable register
  69. IIR    EQU    2            ;Interrupt identification register
  70. LCR    EQU    3            ;Line control register
  71. MCR    EQU    4            ;Modem control register
  72. LSR    EQU    5            ;Line status register
  73. MSR    EQU    6            ;Modem status register
  74. SCR    EQU    7            ;8250 scratch register
  75.  
  76.     ENDS    DATA
  77.  
  78. ;    Code segment declaration
  79.  
  80.     SEGMENT    CODE    BYTE PUBLIC
  81.  
  82.     ASSUME    CS:CODE,DS:DATA
  83.  
  84. ;    Externally accessable procedures defined here
  85.  
  86.         PUBLIC  INT_Handler
  87.     PUBLIC    ComReadCh
  88.     PUBLIC    ComReadChW
  89.     PUBLIC    ComWriteCh
  90.     PUBLIC    ComWriteChW
  91.  
  92. ;********************************************************
  93. ;*                            *
  94. ;*    Subroutines that are used internally        *
  95. ;*                            *
  96. ;********************************************************
  97.  
  98. ; Subroutine:    ChkPort
  99. ; Function:    Check port parameter(s), ensure that port is OPEN
  100. ; Entry:    AL <- Port # (1 - C_MaxCom)
  101. ; Exit:        AL -> Adjusted port # (0 - 3)
  102. ;        AH -> Status register
  103. ;        BX -> Byte array index
  104. ;        DX -> Base address of port
  105. ;        Carry flag SET if parameters & port are OK
  106.  
  107.     PROC    ChkPort        FAR
  108.  
  109. ;    Determine if port # is valid
  110.  
  111.     CMP    AL,[C_MaxCom]        ;Port # > Maximum port # ?
  112.     JA    ChkErr            ; Yes, exit w/error
  113.     CMP    AL,0            ;Port # = 0 (invalid port #)
  114.     JZ    ChkErr            ; Yes, exit w/error
  115.     DEC    AL            ;AL <- Adjusted port #
  116.  
  117. ;    Check if port open
  118.  
  119.     XOR    BH,BH            ;
  120.     MOV    BL,AL            ;BX <- Byte array index
  121.     MOV    AH,[C_PortOpen+BX]    ;AH <- Port-open flag
  122.     CMP    AH,0            ;Port open ?
  123.     JZ    ChkErr            ; No, exit w/error
  124.  
  125. ;    Get status register and base port address in DX
  126.  
  127.     MOV    AH,[C_Status+BX]    ;AH <- Status register
  128.     SHL    BL,1            ;BX <- Word array index
  129.     MOV    DX,[C_PortAddr+BX]    ;DX <- Port address
  130.     SHR    BL,1            ;BX <- Byte array index
  131.     STC                ;Set carry (valid return)
  132.     RET                ;Exit
  133.  
  134. ;    Here if error
  135.  
  136. ChkErr:    CLC                ;Clear carry (invalid return)
  137.     RET                ;Exit
  138.  
  139.     ENDP    ChkPort
  140.  
  141. ;********************************************************
  142.  
  143. ; Subroutine:    PutChar
  144. ; Function:    Place character in transmit buffer (transmit a character)
  145. ; Entry:    AL <- Port # (0-3)
  146. ;        AH <- Status register
  147. ;        BX <- Byte array pointer
  148. ;        CH <- Character to put in buffer
  149. ;        DX <- Base address of port
  150. ; Destroyed:    ES,SI,DI
  151.  
  152. ; Note:    Port address passed is NOT checked for validity.
  153. ;    Subroutine ChkPort will create the proper entry environment
  154.  
  155.     PROC    PutChar        FAR
  156.  
  157. ;    Check for buffer overflow
  158.  
  159.     TEST    AH,00001000b        ;Buffer full ?
  160.     JZ    PutCh1            ; No, continue
  161.     OR    AH,00100000b        ;Set buffer-overflow flag
  162.     JMP    PutChX            ;Exit
  163.  
  164. ;    Increment head pointer
  165.  
  166. PutCh1:    SHL    BL,1            ;BX <- Word array index
  167.     MOV    DI,[C_OutHead+BX]    ;DI <- Output head pointer
  168.     MOV    SI,[C_OutTail+BX]    ;SI <- Output tail pointer
  169.     INC    DI            ;Bump head pointer
  170.     CMP    DI,[C_OutSize+BX]    ;Head >= Buffer size ?
  171.     JB    PutCh2            ; No, continue
  172.     XOR    DI,DI            ; Yes, reset pointer
  173. PutCh2:    MOV    [C_OutHead+BX],DI    ;Save head pointer
  174.  
  175. ;    Place character in buffer
  176.  
  177.     SHL    BL,1            ;BX <- Pointer array index
  178.     LES    BX,[C_OutBufPtr+BX]    ;ES:BX <- Pointer to output buffer
  179.     MOV    [ES:BX+DI],CH        ;Place character in buffer
  180.  
  181. ;    Check for full buffer
  182.  
  183.     CMP    DI,SI            ;Head = Tail (buffer full) ?
  184.     JNZ    PutCh3            ; No, buffer not full
  185.     OR    AH,00001000b        ;Set buffer-full flag
  186.  
  187. ;    Determine if transmitter should be activated
  188.  
  189. PutCh3:    XOR    BH,BH            ;
  190.     MOV    BL,AL            ;BX <- Byte array index
  191.  
  192.     TEST    AH,11000000b        ;Any inhibits (soft/hard hshake) ?
  193.     JNZ    PutChX            ; Yes, do not activate xmit interrupt
  194. ;    TEST    AH,00000100b        ;Buffer empty ?
  195. ;    JZ    PutChX            ; No, xmit interrupt is on already
  196.  
  197.     AND    AH,11111011b        ;Reset buffer-empty flag
  198.     ADD    DL,IER            ;Point to interrupt enable register
  199.     IN    AL,DX            ;AL <- Interrupt enable register
  200.     OR    AL,00000010b        ;Enable transmit interrupt
  201.     OUT    DX,AL            ;Update port
  202.     SUB    DL,IER            ;Point back to base
  203.  
  204. ;    Here to exit
  205.  
  206. PutChX:    MOV    [C_Status+BX],AH    ;Save status byte
  207.     MOV    AL,BL            ;
  208.     RET                ;Exit
  209.  
  210.     ENDP    PutChar
  211.  
  212. ;********************************************************
  213. ;*                            *
  214. ;*    Interrupt service routine for INT3,INT4        *
  215. ;*                            *
  216. ;*        INT3 typically used by COM2, COM4        *
  217. ;*         INT4 typically used by COM1, COM3        *
  218. ;*                            *
  219. ;********************************************************
  220.  
  221.     PROC    INT_Handler     FAR
  222.  
  223.     PUSH    AX            ;Save environment
  224.     PUSH    BX            ;
  225.     PUSH    CX            ;
  226.     PUSH    DX            ;
  227.     PUSH    SI            ;
  228.     PUSH    DI            ;
  229.     PUSH    DS            ;
  230.     PUSH    ES            ;
  231.     PUSH    BP            ;
  232.  
  233.     MASM
  234.     MOV    AX,SEG DATA        ;AX <- Current data segment
  235.     IDEAL
  236.     MOV    DS,AX            ;Set new data segment
  237.  
  238. INT_Id:    XOR    BX,BX            ;BL <- Port # (start at 0)
  239.  
  240. ;    Identify active port
  241.  
  242. IntID1:    MOV    AL,[C_PortOpen+BX]    ;AL <- Port-open flag
  243.     CMP    AL,0            ;Port open ?
  244.     JZ    IntID2            ; No, don't check
  245.     SHL    BL,1            ;BX <- Word array index
  246.     MOV    DX,[C_PortAddr+BX]    ;DX <- Base address of port
  247.     SHR    BL,1            ;BX <- Byte array index
  248.     ADD    DL,IIR            ;Add in offset for IIR
  249.     IN    AL,DX            ;AL <- COMn IIR
  250.     TEST    AL,00000001b        ;Interrupt active on this port ?
  251.     JZ    INT_Active        ; (Bit 0 = 0 if active)
  252. IntID2:    INC    BL            ;Bump port #
  253.     CMP    BL,[C_MaxCom]        ;All ports checked ?
  254.     JB    IntID1            ; No, continue
  255.  
  256. ;    Here to leave interrupt handler
  257.  
  258.     MOV    AL,20h            ;AL <- EOI Acknowledge code
  259.     OUT    20h,AL            ;To 8259 PIC
  260.  
  261.     POP    BP            ;Restore envirionment
  262.     POP    ES            ;
  263.     POP    DS            ;
  264.     POP    DI            ;
  265.     POP    SI            ;
  266.     POP    DX            ;
  267.     POP    CX            ;
  268.     POP    BX            ;
  269.     POP    AX            ;
  270.  
  271.     IRET                ;Interrupt exit
  272.  
  273. ;    Active port (8250) found.
  274. ;    Determine cause of interrupt and execute appropriate handler.
  275. ;    Upon entry into routine, registers are set as follows:
  276. ;    BX <- Byte array index
  277. ;    DX <- Port address
  278.  
  279. INT_Active:
  280.     DEC    DX            ;
  281.     DEC    DX            ;DX <- Base address of COM port
  282.  
  283.     CMP    AL,0            ;IIR = 0 (Modem status change) ?
  284.     JZ    ComMsc            ; Yes
  285.     CMP    AL,2            ;IIR = 2 (Character transmitted) ?
  286.     JZ    ComXmt            ; Yes
  287.     CMP    AL,4            ;IIR = 4 (Character received) ?
  288.     JNZ    Next            ;
  289.     JMP    ComRcv            ; Yes
  290. Next:    CMP    AL,6            ;IIR = 6 (Line status change) ?
  291.     JZ    ComLsc            ; Yes
  292.     JMP    INT_Id            ;Check other ports & exit
  293.  
  294. ;*******************************************************
  295. ;        Line status change
  296. ;        NOTE: Currently unused
  297. ;*******************************************************
  298.  
  299. ComLsc:    ADD    DL,LSR            ;Point to line status register
  300.     IN    AL,DX            ;Get LSR
  301.  
  302. ;    The following code (which disables then enables the transmit
  303. ;    interrupt) is required to compensate for some "buggy" 8250's and
  304. ;    8250-emulating gate arrays.
  305.  
  306.     SUB    DL,LSR            ;Back to base
  307.     ADD    DL,IER            ;Point to interrupt enable register
  308.     IN    AL,DX            ;Get IER
  309.     MOV    AH,AL            ;Save IER
  310.     AND    AL,11111101b        ;Mask transmit interrupt
  311.     OUT    DX,AL            ;Send modified to port
  312.     MOV    AL,AH            ;
  313.     OUT    DX,AL            ;Send original to port
  314.  
  315.     JMP    INT_Id            ;Exit
  316.  
  317. ;*******************************************************
  318. ;        Modem status change
  319. ;*******************************************************
  320.  
  321. ComMsc:    NOP
  322.  
  323. ;    Get modem status & control/status registers
  324.  
  325. Msc0:    ADD    DL,MSR            ;DX <- 8250 MSR port address
  326.     IN    AL,DX            ;AL <- 8250 Modem status
  327.     SUB    DL,MSR            ;Back to base
  328.  
  329.     MOV    CL,[C_Status+BX]    ;CL <- Status register
  330.     MOV    CH,[C_Ctrl+BX]        ;CH <- Control register
  331.  
  332. ;    Control CTS status flag based on CTS status and handshake enable
  333.  
  334.     TEST    CH,00000010b        ;CTS handshake enabled ?
  335.     JZ    Msc2            ; No, ignore CTS status
  336.     TEST    AL,00010000b        ;CTS asserted ?
  337.     JNZ    Msc1            ; Yes, enable transmit
  338.     OR    CL,01000000b        ;CTS inactive - hard handshake on
  339.     JMP    Msc2            ;
  340. Msc1:    AND    CL,10111111b        ;CTS active - hard handshake off
  341. Msc2:    MOV    [C_Status+BX],CL    ;Save status flags
  342.  
  343. ;    Determine if transmitter should be enabled
  344.  
  345. Msc3:    ADD    DL,IER            ;DX <- 8250 IER port address
  346.     IN    AL,DX            ;AL <- Interrupt enable register
  347.     OR    AL,00000010b        ;Enable transmitter by default
  348.     TEST    CL,11000100b        ;Enable transmitter ?
  349.     JZ    Msc4            ; Yes
  350.     AND    AL,11111101b        ; No - disable transmitter
  351. Msc4:    OUT    DX,AL            ;Update IER
  352.     JMP    INT_Id            ;Exit
  353.  
  354. ;*******************************************************
  355. ;        Character transmitted
  356. ;*******************************************************
  357.  
  358. ; Register usage:
  359. ; AH : Status register
  360. ; BX : Array pointer
  361. ; DX : Port address
  362. ; SI : Output tail pointer
  363. ; DI : Output head pointer
  364.  
  365. ;    Get status and control registers
  366.  
  367. ComXmt:    MOV    AH,[C_Status+BX]    ;AH <- Status register
  368.     TEST    AH,00000100b        ;Buffer empty ?
  369.     JNZ    Xmt2            ; Yes, stop transmitter
  370.  
  371. ;    Bump tail pointer
  372.  
  373.     PUSH    BX            ;Save byte array pointer
  374.     SHL    BL,1            ;BX <- Word array pointer
  375.     MOV    SI,[C_OutTail+BX]    ;SI <- Output tail pointer
  376.     MOV    DI,[C_OutHead+BX]    ;DI <- Output head pointer
  377.  
  378.     INC    SI            ;Bump tail pointer
  379.     CMP    SI,[C_OutSize+BX]    ;Tail < Buffer size ?
  380.     JB    Xmt1            ; Yes, proceed normally
  381.     XOR    SI,SI            ; No, reset to 0
  382. Xmt1:    MOV    [C_OutTail+BX],SI    ;Save tail pointer
  383.  
  384. ;    Send character
  385.  
  386.     SHL    BL,1            ;BX <- Pointer array pointer
  387.     LES    BX,[C_OutBufPtr+BX]    ;ES:BX <- Pointer to output buffer
  388.     MOV    AL,[ES:BX+SI]        ;AL <- Character from buffer
  389.     OUT    DX,AL            ;Send
  390.     POP    BX            ;Recover byte array pointer
  391.  
  392. ;    Determine if buffer is empty
  393. ;    Reset output-buffer-full flag & exit
  394.  
  395.     CMP    DI,SI            ;Head = Tail (buffer empty) ?
  396.     JNZ    Xmt2            ; No, continue normally
  397.     OR    AH,00000100b        ;Set buffer-empty flag
  398. Xmt2:    AND    AH,11010111b        ;Reset FULL and OVERFLOW flags
  399.     MOV    [C_Status+BX],AH    ;Save status flags
  400.     JMP    Msc0            ;Exit (check xmit mask)
  401.  
  402. ;*******************************************************
  403. ;        Character received
  404. ;*******************************************************
  405.  
  406. ; Register usage:
  407. ; AL : Status register
  408. ; AH : Control register
  409. ; BX : Array index
  410. ; CL : Character received
  411. ; CH : Temporary storage
  412. ; DX : Port address
  413. ; SI : Input tail pointer
  414. ; DI : Input head pointer
  415.  
  416. ComRcv:    IN    AL,DX            ;
  417.     MOV    CL,AL            ;CL <- Received character
  418.  
  419. ;    Check for software handshake
  420.  
  421.     MOV    AL,[C_Status+BX]    ;AL <- Status byte
  422.     MOV    AH,[C_Ctrl+BX]        ;AH <- Control byte
  423.     TEST    AH,00000100b        ;Software handshake enabled ?
  424.     JZ    Rcv3            ; No, don't check software handshake
  425.     CMP    CL,[C_StopChar+BX]    ;STOP TRANSMIT character ?
  426.     JZ    Rcv1            ; Yes
  427.     CMP    CL,[C_StartChar+BX]    ;START TRANSMIT character ?
  428.     JNZ    Rcv3            ; No
  429.  
  430. ;    Soft-handshake character received.
  431. ;    Activate or deactive transmitter depending on status
  432.  
  433.     AND    AL,01111111b        ;Reset soft-handshake flag (start)
  434.     JMP    Rcv2            ;Save status & exit
  435. Rcv1:    OR    AL,10000000b        ;Set soft-handshake flag (stop)
  436. Rcv2:    MOV    CL,AL            ;Routines in MSC2 require status in CL
  437.     JMP    Msc2            ;Exit (xmit interrupt controlled here)
  438.  
  439. ;    Check for XL3 verification sequence
  440.  
  441. ;    Note : This code is here to provide the capability to communicate
  442. ;    with a Pyrotronics XL3 fire alarm panel (since this is why these
  443. ;    routines were developed in the first place).  In almost all cases
  444. ;    they will never be needed by the "normal" user.
  445.  
  446. Rcv3:    TEST    AH,10000000b        ;XL3 mode active ?
  447.     JZ    Rcv3e            ; No, ignore
  448.     MOV    DI,BX            ;Save array index
  449.     MOV    BL,[C_XL3Ptr+BX]    ;BX <- Current check position
  450.     CMP    CL,[BYTE CS:XL3Str+BX]    ;Check current char vs. escape sequence
  451.     JNZ    Rcv3d            ;Continue normally if no match
  452.  
  453. ;    Possible XL3 string match
  454.  
  455.     MOV    CH,BL            ;CH <- String index
  456.     MOV    BX,DI            ;Recover array index
  457.     INC    CH            ;Bump index
  458.     CMP    CH,OFFSET XL3Len    ;End of string ?
  459.     JAE    Rcv3a            ; Yes, send answerback
  460.     MOV    [C_XL3Ptr+BX],CH    ;Save string index
  461.     JMP    INT_Id            ;Exit
  462.  
  463. ;    XL3 identify sequence detected.  Send answerback.
  464.  
  465. Rcv3a:    MOV    SI,OFFSET AnsBak    ;SI <- Pointer to answerback string
  466.     MOV    AH,AL            ;Put status byte in AH (for PutChar)
  467.     MOV    AL,BL            ;Put port # in AL (for PutChar)
  468. Rcv3b:    MOV    CH,[CS:SI]        ;CH <- Char from answerback string
  469.     CMP    CH,0            ;End of string ?
  470.     JZ    Rcv3c            ; Yes, exit now
  471.     PUSH    SI            ;Save SI (modified by PutChar)
  472.     CALL    PutChar            ;Transmit character
  473.     POP    SI            ;Recover SI
  474.     INC    SI            ;Point to next char in string
  475.     JMP    Rcv3b            ;Continue until string sent    
  476.  
  477. Rcv3c:    MOV    [C_XL3Ptr+BX],0        ;Reset string index
  478.     JMP    INT_Id            ;Exit
  479.  
  480. ;    XL3 identify string mismatch - reset pointer & continue
  481.  
  482. Rcv3d:    MOV    BX,DI            ;Recover array index
  483.     MOV    [C_XL3Ptr+BX],0        ;Reset string index
  484.  
  485. ;    Clear buffer empty flag / check for buffer overflow
  486.     
  487. Rcv3e:    AND    AL,11111110b        ;Clear buffer-empty flag
  488.     TEST    AL,00000010b        ;Buffer full ?
  489.     JZ    Rcv4            ; No, continue
  490.     OR    AL,00010000b        ;Set overflow flag
  491.     JMP    Rcv10            ;Exit
  492.  
  493. ;    Bump receive buffer pointer
  494.  
  495. Rcv4:    SHL    BL,1            ;BX <- Word array index
  496.     MOV    DI,[C_InHead+BX]    ;DI <- Input head pointer
  497.     MOV    SI,[C_InTail+BX]    ;SI <- Input tail pointer
  498.  
  499.     INC    DI            ;Bump buffer pointer
  500.     CMP    DI,[C_InSize+BX]    ;Head > buffer size ?
  501.     JB    Rcv5            ; No, continue
  502.     XOR    DI,DI            ; Yes, reset pointer
  503.  
  504. ;    Store character in buffer
  505.  
  506. Rcv5:    PUSH    BX            ;Save word array pointer
  507.     MOV    [C_InHead+BX],DI    ;Save updated input head pointer
  508.     SHL    BL,1            ;BX <- Doubleword array index
  509.     LES    BX,[C_InBufPtr+BX]    ;ES:BX <- Pointer to buffer
  510.     MOV    [ES:BX+DI],CL        ;Save character in buffer
  511.     POP    BX            ;Recover word array pointer
  512.  
  513. ;    Check for full buffer
  514.  
  515.     CMP    SI,DI            ;Tail = Head ?
  516.     JNZ    Rcv6            ;If Tail <> Head, buffer is not full
  517.     OR    AL,00000010b        ;Set buffer-full flag
  518.     JMP    Rcv8            ;Reset RTS and exit
  519.  
  520. ;    Check for near-full buffer (buffer used >= RTSOff)
  521.  
  522. Rcv6:    CMP    SI,DI            ;Tail <= Head ?
  523.     JBE    Rcv7            ; Yes, use standard formula
  524.     SUB    SI,DI            ;SI <- Tail - Head
  525.     MOV    DI,[C_InSize+BX]    ;DI <- Input buffer size
  526. Rcv7:    SUB    DI,SI            ;DI <- Head - Tail (amt used)
  527.     CMP    DI,[C_RTSOff+BX]    ;Used < Limit ?
  528.     JB    Rcv9            ; Yes, leave RTS on
  529.  
  530. ;    Buffer is (near) full, force RTS off & exit
  531.  
  532. Rcv8:    TEST    AH,00000001b        ;RTS handshake enabled ?
  533.     JZ    Rcv9            ; No, exit now
  534.  
  535.     MOV    CH,AL            ;Keep status byte
  536.     ADD    DL,MCR            ;DX <- Address of modem control reg.
  537.     IN    AL,DX            ;AL <- MCR
  538.     AND    AL,11111101b        ;Disable RTS
  539.     OUT    DX,AL            ;Update MCR
  540.     SUB    DL,MCR            ;DX <- Base of port
  541.     MOV    AL,CH            ;Recover status byte
  542.  
  543. ;    Exit - receive
  544.  
  545. Rcv9:    SHR    BL,1            ;BX <- Byte array index
  546. Rcv10:    MOV    [C_Status+BX],AL    ;Save status byte
  547.  
  548. ;    The following code corrects a "bug" present in some 8250's
  549.  
  550.     ADD    DL,IER            ;DX <- Interrupt Enable Register
  551.     IN    AL,DX            ;AL <- IER
  552.     MOV    AH,AL            ;Save IER
  553.     AND    AL,11111101b        ;Mask off transmit interrupt
  554.     OUT    DX,AL            ;Send to IER
  555.     MOV    AL,AH            ;
  556.     OUT    DX,AL            ;Restore original IER state
  557.  
  558.     JMP    INT_Id            ;Check for pending INTs and exit
  559.  
  560.     ENDP    INT_Handler
  561.  
  562. ;********************************************************
  563. ;*                            *
  564. ;*    Start of Pascal low-level procedures        *
  565. ;*                            *
  566. ;********************************************************
  567. ;*                            *
  568. ;*    Function ComReadCh(ComPort:Byte) : Char        *
  569. ;*                            *
  570. ;********************************************************
  571.  
  572.     PROC    ComReadCh     FAR
  573.  
  574. ;    Check port # for validity
  575.  
  576.     CLI                ;Interrupts disabled
  577.  
  578.     MOV    BX,SP            ;BX <- Stack pointer
  579.     MOV    AL,[SS:BX+4]        ;AL <- Port #
  580.     CALL    ChkPort            ;Check port # for validity
  581.     JNC    ComRd1            ; Invalid port, exit
  582.  
  583. ;    Check buffer, return null if empty
  584.  
  585.     MOV    AH,[C_Status+BX]    ;AH <- Status byte
  586.     TEST    AH,00000001b        ;Buffer empty ?
  587.     JZ    ComRd2            ; No, continue normally
  588.  
  589. ;    Buffer empty, port not open or port # invalid - exit
  590.  
  591. ComRd1:    MOV    CH,0            ;Return null (port error or empty)
  592. ComRdX:    MOV    AL,CH            ;AL <- Char from buffer
  593.     STI                ;Enable interrupts
  594.     RET    2            ;Exit
  595.  
  596. ;    Increment tail pointer
  597. ;    NOTE: Entry point for ComReadChW
  598.  
  599. ComRd2:    SHL    BL,1            ;BX <- Word array index
  600.     MOV    SI,[C_InTail+BX]    ;SI <- Tail pointer
  601.     MOV    DI,[C_InHead+BX]    ;DI <- Input head pointer
  602.     INC    SI            ;Bump tail pointer
  603.     CMP    SI,[C_InSize+BX]    ;Tail past end of buffer ?
  604.     JB    ComRd3            ; No, continue
  605.     XOR    SI,SI            ; Yes, reset pointer
  606. ComRd3:    MOV    [C_InTail+BX],SI    ;Save updated tail pointer
  607.  
  608. ;    Get character from buffer
  609.  
  610.     SHL    BL,1            ;BX <- Pointer array index
  611.     LES    BX,[C_InBufPtr+BX]    ;ES:BX <- Pointer to input buffer
  612.     MOV    CH,[ES:BX+SI]        ;CH <- Character from buffer
  613.  
  614. ;    Clear FULL and OVERFLOW flags
  615. ;    Check for empty buffer
  616.  
  617.     XOR    BH,BH            ;
  618.     MOV    BL,AL            ;Byte array index
  619.     AND    AH,11101101b        ;Reset FULL and OVERFLOW status flags
  620.     CMP    DI,SI            ;Head = Tail (buffer empty ?)
  621.     JNZ    ComRd4            ; No, continue normally
  622.     OR    AH,00000001b        ; Yes, set empty flag
  623. ComRd4:    MOV    [C_Status+BX],AH    ;Save status byte
  624.  
  625. ;    Check for RTS assert (Used <= RTSOn)
  626. ;    Variable USED (# of used bytes in buffer) calculated as :
  627. ;      IF (Head >= Tail) THEN
  628. ;        Used = Head-Tail
  629. ;      ELSE
  630. ;        Used = BufferSize - (Tail-Head)
  631.  
  632.     SHL    BL,1            ;BX <- Word array index
  633.     CMP    DI,SI            ;Head >= Tail ?
  634.     JAE    ComRd5            ; Yes, use alternate formula
  635.     SUB    SI,DI            ;SI <- Tail - Head
  636.     MOV    DI,[C_InSize+BX]    ;DI <- Input buffer size
  637. ComRd5:    SUB    DI,SI            ;DI <- Amount of buffer used
  638.     CMP    DI,[C_RTSOn+BX]        ;Used > Limit ?
  639.     JA    ComRdX            ; Yes, not ready for receive
  640.  
  641. ;    Here to assert RTS    
  642.  
  643.     SHR    BL,1            ;BX <- Byte array index
  644.     MOV    AL,[C_Ctrl+BX]        ;AL <- Control byte
  645.     TEST    AL,00000001b        ;RTS handshaking enabled ?
  646.     JZ    ComRdX            ; No, exit now
  647.  
  648.     ADD    DL,MCR            ;DX <- 8250 MCR port address
  649.     IN    AL,DX            ;AL <- 8250 MCR
  650.     OR    AL,00000010b        ;Assert RTS
  651.     OUT    DX,AL            ;Send to port
  652.     JMP    ComRdX            ;Exit
  653.  
  654.     ENDP    ComReadCh
  655.  
  656. ;********************************************************
  657. ;*                            *
  658. ;*    Function ComReadChW(ComPort:Byte) : Char    *
  659. ;*                            *
  660. ;********************************************************
  661.  
  662.     PROC    ComReadChW    FAR
  663.  
  664. ;    Check for valid port
  665.  
  666.     MOV    BX,SP            ;BX <- Stack pointer
  667.     MOV    AL,[SS:BX+4]        ;AL <- Port #
  668.     CALL    ChkPort            ;Port # valid ?
  669.     JNC    ComRWX            ; No, exit now
  670.  
  671. ;    Wait for character
  672.  
  673. ComRW1:    MOV    AH,[C_Status+BX]    ;AL <- Status byte
  674.     TEST    AH,00000001b        ;Input buffer empty ?
  675.     JNZ    ComRW1            ; Yes, continue waiting
  676.  
  677.     CLI                ;Disable interrupts
  678.     JMP    ComRd2            ;Proceed with normal read
  679.  
  680. ;    Here if error
  681.  
  682. ComRWX:    MOV    AL,0            ;Return null result
  683.     RET    2            ;Exit
  684.  
  685.     ENDP    ComReadChW
  686.  
  687. ;********************************************************
  688. ;*                            *
  689. ;*    Procedure ComWriteCh(ComPort:Byte; Var Ch:Char)    *
  690. ;*                            *
  691. ;********************************************************
  692.  
  693.     PROC    ComWriteCh    FAR
  694.  
  695. ;    Check port # for validity
  696.  
  697.     MOV    BX,SP            ;Point BX at parameters
  698.     MOV    AL,[SS:BX+6]        ;AL <- Port #
  699.     MOV    CH,[SS:BX+4]        ;CH <- Character to send
  700.     CALL    ChkPort            ;Check port for validity
  701.     JNC    ComWr1            ;Exit if not valid
  702.  
  703.     CLI                ;Disable interrupts
  704.     CALL    PutChar            ;Place character in appropriate buffer
  705.     STI                ;Enable interrupts
  706.  
  707. ComWr1:    RET    4            ;Exit
  708.  
  709.     ENDP    ComWriteCh
  710.  
  711. ;********************************************************
  712. ;*                            *
  713. ;*   Procedure ComWriteChW(ComPort:Byte; Var Ch:Char)    *
  714. ;*                            *
  715. ;********************************************************
  716.  
  717.     PROC    ComWriteChW    FAR
  718.  
  719. ;    Check port # for validity
  720.  
  721.     MOV    BX,SP            ;Point BX at parameters
  722.     MOV    AL,[SS:BX+6]        ;AL <- Port #
  723.     MOV    CH,[SS:BX+4]        ;CH <- Character to send
  724.     CALL    ChkPort            ;Check port for validity
  725.     JNC    ComWW2            ;Exit if not valid
  726.  
  727. ;    Wait for buffer to open up
  728.  
  729. ComWW1:    MOV    AH,[C_Status+BX]    ;AH <- Status byte
  730.     TEST    AH,00101000b        ;Buffer filled ?
  731.     JNZ    ComWW1            ; Yes, loop until open
  732.  
  733.     CLI                ;Turn off interrupts
  734.     CALL    PutChar            ;Place character in buffer
  735.     STI                ;Enable interrupts
  736.  
  737. ComWW2:    RET    4            ;Exit
  738.  
  739.     ENDP    ComWriteChW
  740.  
  741. ;********************************************************
  742.  
  743. XL3Len    EQU    3            ;Length of XL3 string
  744. XL3Str:    DB    1Bh,5Bh,63h        ;ESC [ c    (From XL3)
  745. AnsBak:    DB    1Bh,5Bh,38h,32h,30h,00h    ;ESC [ 8 2 0    (To XL3)
  746.  
  747.     ENDS    CODE
  748.     END
  749.